//
// Created by DengLibin on 2019/1/30 0030.
//

#ifndef WXWIDGETS_MYTHREAD_H
#define WXWIDGETS_MYTHREAD_H

#include <wx/thread.h>
#include <wx/wx.h>
#include <iostream>
using namespace std;
/**
有两种不同的线程,一种线程你在启动之后就可以忘记它的存在,而另外一种,你需要等待它返回
一个结果.前者我们称为分离线程,后者称为联合线程. 线程的类型是通过调用wxThread的构造函数
时传递的参数是wxThreadKind::wxTHREAD_DETACHED还是wxThreadKind::wxThrEAD_JOINABLE来决定的,联合线程的返回值是由对其成
员函数Wait的调用返回的,而对于分离线程,不可以调用Wait函数.
线程中止:
分离线程是自动结束和释放自己的.而对于联合线程,你可以简单的调用wxThread::Wait函数
 * */
class MyThread : public wxThread {
private:
    static wxMutex * mutex; //互斥锁
public:
    static int x; // 静态成员不能在类内初始化 ， 常量成员也不能在类内初始化， 静态常量成员可以在类内初始化
    MyThread(wxThreadKind threadKind);
    void *Entry() HAVE_OVERRIDE;
    /**
     * 析构函数释放与线程关联的资源
     */
    ~MyThread();
};


#endif //WXWIDGETS_MYTHREAD_H

/**线程相关：
 *线程基本上是通过程序执行的路径。
线程有时被称为轻量级进程，但线程和进程之间的根本区别在于，不同进程的内存空间是分开的，而所有线程共享相同的地址空间。
虽然它使得在多个线程之间共享公共数据变得更加容易，但是它也使得在脚上射击自己变得更加容易，因此建议小心使用同步对象，
 例如互斥锁(参见wxMutex)或临界区(参见wxCriticalSection)。另外，不要创建全局线程对象，因为它们在构造函数中分配内存，这会给内存检查系统带来问题

 类型的wxThreads
wxWidgets中有两种类型的线程:分离线程和可连接线程，它们以POSIX线程API为模型。这与所有线程都可连接的Win32 API不同。
默认情况下，wxThreads在wxWidgets中使用分离的行为。分离的线程在完成之后会删除它们自己，或者在完成处理时由它们自己删除，或者通过调用delete()删除，因此必须在堆上创建(例如，通过新操作符)。
通常，您需要存储所分配的分离wxThreads的实例，以便调用函数

 相反，可连接线程在完成处理时不会删除自己，因此在堆栈上创建它们是安全的。可接合线程还提供了通过Wait()从Entry()获取返回值的能力。
 你不应该急于创造可接合线程,但是,因为这也有一个缺点:你必须等待()可接合线程或所使用的系统资源永远不会被释放,你也必须删除相应的wxThread
 对象自己如果你没有创建堆栈。相反，分离的线程是“发射后忘记”
 *
 wxThread删除
 *可连接线程：无论它是否终止，您都应该在可连接线程上调用Wait()来释放其内存，如wxThreads类型中所述。如果您在堆上创建了一个可连接的线程，请记住使用delete操作符或类似的方法手动删除它，
 * 因为只有分离的线程才能处理这种类型的内存管理。
 *
 *分离的线程： 由于分离的线程在完成处理后会删除它们自己，所以在调用一个线程上的例程时应该小心。如果您确定线程仍在运行并希望结束它，
 * 可以调用Delete()来优雅地结束它(这意味着在调用Delete()之后将删除线程)。应该建议您永远不要尝试使用delete操作符或类似的方法删除已分离的线程
 *
 * 如前所述，Wait()或Delete()函数分别尝试优雅地终止可连接线程和分离线程。它们通过等待相关线程调用TestDestroy()
 * 或结束处理(即从wxThread::Entry返回)来完成此操作
 *
 *显然，如果线程确实调用TestDestroy()而没有结束，那么调用Wait()或Delete()的线程将停止。
 * 这就是为什么在线程的Entry()例程中尽可能频繁地调用TestDestroy()并在它返回true时立即退出非常重要
 *
 * 最后，您可以通过Kill()立即结束线程。但是，强烈建议您不要这样做，因为它不会释放与对象关联的资源(尽管分离线程的wxThread对象仍然会被删除)，
 * 并且会使C运行时库处于未定义的状态。
 *
 * wxWidgets在辅助线程中调用
 * 除了“主应用程序线程”(例如，运行wxApp::OnInit()或主函数运行的线程)之外的所有线程都被认为是“辅助线程”
 *
 *GUI调用，例如对wxWindow或wxBitmap的调用，在辅助线程中是极其不安全的，可能会提前结束应用程序。这
 * 是由于几个原因，包括底层本机API和wxThread不运行与MFC等其他API类似的GUI事件循环
 *
 *一些wxWidgets端口的解决方案是在任何GUI调用之前调用wxMutexGUIEnter()，然后在任何GUI调用之后调用wxMutexGUILeave()。但是，推荐的方法是通过wxQueueEvent()发布的事件在主线程中简单地处理GUI调用。
 * 但是，这并不意味着对这些类的调用是线程安全的，因为大多数wxWidgets类都不是线程安全的，包括wxString。
 *
 *
 *不要轮询wxThread
 *wxThread用户体验一个常见问题是,他们在主线程时不时会通过 IsRunning()检查线程是否已经结束,却发现他们的应用程序遇到问题,因为线程（分离线程）使用默认行为已删除。
 * 当然，它们会尝试使用可连接的线程来代替前面的行为。然而，轮询wxThread何时结束通常不是一个好主意——实际上，如果可能的话，
 * 应该避免在任何运行wxThread的线程上调用例程。相反，找到一种方法在线程结束时通知自己。通常您只需要通知主线程，在这种情况下，
 * 您可以通过wxQueueEvent()将事件发布到它。在次要线程的情况下，当线程即将完成处理和/或设置变量的值时，您可以调用另一个类的例程，
 * 可能使用互斥(参见wxMutex)和/或其他同步方法(如果需要的话)。
 *
 * API:
 * Create():
 * 线程对象是在挂起状态下创建的，您应该调用Run()来开始运行它。
 * 您可以选择指定要分配给它的堆栈大小(在不支持显式设置堆栈的平台上忽略，例如。Unix系统中没有pthread_attr_setstacksize)。
 * note:
 *It is not necessary to call this method since 2.9.5, Run() will create the thread internally.
 * You only need to call Create() if you need to do something with the thread (e.g. pass its ID to an external library) before it starts.
 * 从2.9.5版本以后 可以不用调用Create()方法，run()方法内部会创建线程，如果想在线程开启之前做一些其他操作，那么可以调用Create()
 *
 * Delete()
 *调用Delete()可以在线程调用TestDestroy()或完成处理时优雅地终止分离的线程
 *
 * Entry()
 * 这是线程的入口点。
这个函数是纯虚函数，必须由任何派生类实现。线程执行将从这里开始。
返回的值是线程退出代码，它只对可连接线程有用，是Wait()返回的值。这个函数是由wxWidgets本身调用的，不应该直接调用

  Exit()
这是wxThread类的一个受保护函数，因此只能从派生类中调用。
它也只能在这个线程的上下文中调用，即一个线程只能从它自己退出，而不能从另一个线程退出。
此函数将终止操作系统线程(即停止相关的执行路径)，并为分离的线程删除相关的c++对象。在退出之前将调用OnExit()。

 GetCPUCount()
 static int wxThread::GetCPUCount()
 返回系统cpu的数量，如果该值未知，则返回-1。
对于多核系统，返回值通常是内核总数，因为OS通常将单个N核CPU抽象为N个不同的内核。

 GetCurrentId()
static wxThreadIdType wxThread::GetCurrentId  ()
 将当前线程的平台特定线程ID作为long返回。
这可以用来唯一地标识线程，即使它们不是wxThreads。

GetId()
获取线程标识符:这是一个依赖于平台的编号，在整个系统存在期间唯一标识线程(即可以重用线程标识符)。

GetKind()
返回在ctor中给定的线程类型


 GetMainId()
static wxThreadIdType wxThread::GetMainId  ()
 返回主线程的线程ID

 GetPriority()
 获取线程的优先级，在0(最低)和100(最高)之间。

 IsAlive()
 如果线程是活动的(即启动而不是终止)，返回true。
注意，这个函数只能安全地与可连接的线程一起使用，而不能与分离的线程一起使用，因为后者会删除它们自己，所以当真正的线程不再活动时，
 不可能调用这个函数，因为wxThread对象不再存在。

 IsDetached()
如果线程是分离线程，则返回true;如果线程是可连接线程，则返回false。

 IsMain()
 如果调用线程是主应用程序线程，则返回true。
wxWidgets上下文中的主线程是初始化库的线程

 IsPaused()
如果线程暂停，返回true。

 IsRunning()
 如果线程正在运行，则返回true。
此方法只能安全地用于可接合线程


  Kill()
  立即终止目标线程
这个函数很危险，应该非常小心地使用”(在任何可能的情况下都不要使用)!分配给线程的资源不会被释放，C运行时库的状态可能变得不一致。
 对于分离的线程使用Delete()，对于可连接的线程使用Wait()。对于分离的线程，Kill()也将删除关联的c++对象。
 但是，对于可连接线程，这不会发生，这意味着您仍然必须自己删除wxThread对象，以避免内存泄漏。在这两种情况下，
 都不会调用濒死线程的OnExit()，因此不会执行特定于线程的清理。这个函数只能从另一个线程上下文中调用，即线程不能杀死自己。
 对于没有运行或暂停的线程(在后一种情况下，将首先恢复线程)调用此函数也是一个错误，如果这样做，将返回一个wxTHREAD_NOT_RUNNING错误。

 MSWGetHandle()
 获取本机线程句柄。
此方法只存在于wxMSW(windows系统)中，在可移植代码中使用GetId()


 OnExit()
 线程退出时调用。
这个函数是在与wxThread对象关联的线程的上下文中调用的，而不是在主线程上下文中调用的。如果线程被Kill()杀死，则不会调用此函数。
永远不要直接调用这个函数。

 Pause()
 线程挂起。
在一些实现(Win32)中，线程会立即挂起，在另一些实现中，它只会在下一次调用TestDestroy()时挂起(因此，如果线程根本不调用它，它就不会挂起)。
只能从另一个线程上下文中调用此函数。

 Resume()
 恢复暂停()调用所挂起的线程。
只能从另一个线程上下文中调用此函数。

 Run()
启动线程执行。注意，一旦您运行()一个分离的线程，您对线程指针所做的任何函数调用(您必须在堆上分配它)都是“不安全的”;
 例如，线程可能在Run()之后的任何时刻终止，指针可能处于悬空状态。有关安全操作分离线程的示例，请参见wxThreads的类型。
 只能从另一个线程上下文中调用此函数。最后，请注意，一旦线程完成并返回其Entry()函数，您就不能再次对其调用Run()
 (在调试构建中断言将失败，或者在发行版构建中将返回wxTHREAD_RUNNING)。

 SetConcurrency()
static bool wxThread::SetConcurrency  ( size_t  level )
 设置此进程的线程并发级别。
这大致是系统试图调度并行运行的线程数。level的值0可用于设置默认值。
成功true，否则返回false(例如，如果这个函数没有在这个平台上实现——目前除了Solaris之外的所有平台)。

 SetPriority()
 设置线程的优先级，在0(最低)和100(最高)之间。几个常量：
wxPRIORITY_MIN: 0
wxPRIORITY_DEFAULT: 50
wxPRIORITY_MAX: 100
注意，在MSW实现中，当前只能在使用CreateThread()创建线程之后设置线程优先级。但是在所有平台上，
可以在使用Run()启动线程之前或之后调用这个方法。

Sleep()
 static void wxThread::Sleep  ( unsigned long  milliseconds )
 在给定的时间内暂停线程执行。
这与wxMilliSleep()相同。

 TestDestroy()
 线程应该定期调用这个函数，以确保对Pause()和Delete()的调用能够正常工作。
如果返回true，线程应该尽快退出。注意，在某些平台(POSIX)下，Pause()的实现也依赖于被调用的这个函数，因此不调用它会阻止停止和挂起线程工作。

 This()
 static wxThread* wxThread::This  ()
 返回调用线程的线程对象。
如果调用线程是主(GUI)线程，则返回NULL，但是应该使用IsMain()来测试线程是否真的是主线程，因为对于没有使用wxThread类创建的线程，
 也可能返回NULL。一般来说，此类线程的返回值是未定义的。

 Wait()
等待可连接线程终止，并在出错时返回从Entry()或“(ExitCode)-1”返回的线程值。注意，与Delete()不同，这个函数不以任何方式取消线程，
 因此调用者需等待线程退出。您只能等待()可连接(而非分离)线程。只能从另一个线程上下文中调用此函数。

 Yield()
static void wxThread::Yield  ()
 将线程的其余时间片分配给系统，允许其他线程运行。 强烈建议不要使用该函数， 因为在许多情况下，它表明线程模型的设计缺陷(就像使用Sleep()函数一样)。
 * */

